package com.ssy.lingxi.marketing.serviceimpl.component.activity;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.marketing.ActivityTypeEnum;
import com.ssy.lingxi.common.constant.marketing.BelongTypeEnum;
import com.ssy.lingxi.common.constant.member.AbilitySuitableMemberEnum;
import com.ssy.lingxi.common.constant.member.PlatformSuitableMemberEnum;
import com.ssy.lingxi.common.model.bo.MemberAndRoleIdBO;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.marketing.entity.activity.*;
import com.ssy.lingxi.marketing.model.bo.*;
import com.ssy.lingxi.marketing.model.constant.CommonBooleanEnum;
import com.ssy.lingxi.marketing.model.constant.MerchantActivityInnerStatusEnum;
import com.ssy.lingxi.marketing.model.constant.PlatformActivityOuterStatusEnum;
import com.ssy.lingxi.marketing.repository.ActivityGoodsRepository;
import com.ssy.lingxi.marketing.repository.ActivityMemberLevelRepository;
import com.ssy.lingxi.marketing.repository.MerchantActivityRepository;
import com.ssy.lingxi.marketing.repository.PlatformActivityRepository;
import com.ssy.lingxi.marketing.serviceimpl.component.SuitableFieldComponent;
import com.ssy.lingxi.marketing.serviceimpl.component.SuitableMemberInfoComponent;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.AtSubMemberSuitableMemberVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.PfSubMemberSuitableMemberVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 活动规则校验组件
 * @author yzc
 * @version 2.0.0
 * @date 2021/9/17
 */
@Slf4j
@Component
public class ActivityCheckRuleComponent {

    @Resource
    private JPAQueryFactory queryFactory;
    @Resource
    private ActivityGoodsRepository goodsRepository;
    @Resource
    private PlatformActivityRepository platformActivityRepository;
    @Resource
    private MerchantActivityRepository merchantActivityRepository;
    @Resource
    private SuitableMemberInfoComponent suitableMemberInfoComponent;
    @Resource
    private ActivityMemberLevelRepository activityMemberLevelRepository;


    /**
     * @see #getFilterSkuIdByJsonObj
     */
    public Set<Long> getFilterSkuId(Integer activityType, ActivityDefinedBO activityDefinedBO, Long startTime, Long endTime) {
        JSONObject jsonObject = JSONUtil.parseObj(activityDefinedBO);
        return this.getFilterSkuIdByJsonObj(activityType, jsonObject, startTime, endTime);
    }

    /**
     * 获取要过滤的skuId
     * 备注: 由yzc迁移并修改代码
     * @author fhj
     * @param activityType  活动类型
     * @param activityDefinedBO 活动定义
     * @param startTime     活动开始时间
     * @param endTime       活动结束时间
     * @return 返回需要过滤的skuId
     */
    public Set<Long> getFilterSkuIdByJsonObj(Integer activityType, JSONObject activityDefinedBO, Long startTime, Long endTime) {
        // 允许叠加活动所勾选的选项(如无叠加活动, 则为空集合)
        List<Integer> allowActivity = Optional.ofNullable(activityDefinedBO.getJSONArray("allowActivity")).map(jsonArray -> jsonArray.toList(Integer.class)).orElse(Collections.emptyList());
        // 允许叠加优惠券所勾选的选项(如无叠加优惠券, 则为null)
        Integer allowCoupon = Optional.ofNullable(activityDefinedBO.getBool("allowCoupon")).map(v -> v ? CommonBooleanEnum.YES.getCode() : CommonBooleanEnum.NO.getCode()).orElse(null);

        // 要过滤的skuId
        Set<Long> platformFilterSkuSet = getPlatformFilterSku(activityType, allowCoupon, allowActivity, startTime, endTime);
        Set<Long> merchantFilterSkuSet = getMerchantFilterSku(activityType, allowCoupon, allowActivity, startTime, endTime);
        platformFilterSkuSet.addAll(merchantFilterSkuSet);
        return platformFilterSkuSet;
    }

    /**
     * 获取平台活动过滤的sku
     * @param activityType  活动类型
     * @param allowCoupon 是否叠加优惠券 0-否 1-是
     * @param allowActivity 可叠加的活动
     * @param startTime     活动开始时间
     * @param endTime       活动结束时间
     * @return 返回需要过滤的skuId
     */
    private Set<Long> getPlatformFilterSku(Integer activityType, Integer allowCoupon, List<Integer> allowActivity, Long startTime, Long endTime) {
        // 根据活动类型、允许叠加活动类型、活动开始时间、活动结束时间，查询出要过滤的平台营销活动
        QPlatformActivityDO platformActivityDO = QPlatformActivityDO.platformActivityDO;
        BooleanBuilder predicates = new BooleanBuilder();
        // 同一活动时间段内
        predicates.and(
                platformActivityDO.startTime.lt(startTime).and(platformActivityDO.endTime.gt(startTime)).or(
                        platformActivityDO.startTime.lt(endTime).and(platformActivityDO.endTime.gt(startTime))
                )
        );
        //活动结束sku可再次加入
        predicates.and(platformActivityDO.outerStatus.notIn(PlatformActivityOuterStatusEnum.getAllowRejoinActivityStatusList()));
        // 判断该活动是否允许叠加活动类型
        if (ActivityTypeEnum.checkFold(activityType)) {
            // 如果是叠加活动, 则排除已勾选可叠加的活动(叠加优惠券条件不一样, 不排除)
            if (!CollectionUtils.isEmpty(allowActivity)) {
                BooleanBuilder orPredicates = new BooleanBuilder();
                orPredicates.or(platformActivityDO.activityType.in(allowActivity));
                if (Objects.nonNull(allowCoupon)) {
                    orPredicates.and(platformActivityDO.allowCoupon.ne(allowCoupon));
                }

                orPredicates.or(platformActivityDO.activityType.notIn(allowActivity));

                predicates.and(orPredicates);
            }
        }

        // 查出已经排除了的活动
        List<PlatformActivityDO> ptActivityList = queryFactory.select(platformActivityDO).from(platformActivityDO).where(predicates).fetch();
        if (CollectionUtil.isEmpty(ptActivityList)) {
            return Collections.emptySet();
        }

        // 根据平台营销活动获取要过滤的skuId
        List<Long> ptActivityListId = ptActivityList.stream().map(PlatformActivityDO::getId).collect(Collectors.toList());
        List<ActivityGoodsDO> ptGoodsList = goodsRepository.findByBelongTypeAndActivityIdIn(BelongTypeEnum.PLATFORM.getCode(), ptActivityListId);

        return ptGoodsList.stream().map(ActivityGoodsDO::getSkuId).collect(Collectors.toSet());
    }

    /**
     * 获取商家活动过滤的sku
     * @param activityType  活动类型
     * @param allowCoupon 是否叠加优惠券
     * @param allowActivity 可叠加的活动
     * @param startTime     活动开始时间
     * @param endTime       活动结束时间
     * @return 返回需要过滤的skuId
     */
    private Set<Long> getMerchantFilterSku(Integer activityType, Integer allowCoupon, List<Integer> allowActivity, Long startTime, Long endTime) {
        // 商家营销活动
        QMerchantActivityDO merchantActivityDO = QMerchantActivityDO.merchantActivityDO;
        BooleanBuilder predicates = new BooleanBuilder();
        // 同一活动时间段内
        predicates.and(
                merchantActivityDO.startTime.lt(startTime).and(merchantActivityDO.endTime.gt(startTime)).or(
                        merchantActivityDO.startTime.lt(endTime).and(merchantActivityDO.endTime.gt(startTime))
                )
        );
        //活动结束sku可再次加入
        predicates.and(merchantActivityDO.innerStatus.ne(MerchantActivityInnerStatusEnum.END.getCode()));
        // 判断该活动是否允许叠加活动类型
        if (ActivityTypeEnum.checkFold(activityType)) {
            // 如果是叠加活动, 则排除已勾选可叠加的活动(叠加优惠券条件不一样, 不排除)
            if (!CollectionUtils.isEmpty(allowActivity)) {
                BooleanBuilder orPredicates = new BooleanBuilder();
                orPredicates.or(merchantActivityDO.activityType.in(allowActivity));
                if (Objects.nonNull(allowCoupon)) {
                    orPredicates.and(merchantActivityDO.allowCoupon.ne(allowCoupon));
                }
                orPredicates.or(merchantActivityDO.activityType.notIn(allowActivity));

                predicates.and(orPredicates);
            }
        }

        // 查出已经排除了的活动
        List<MerchantActivityDO> mcActivityList = queryFactory.select(merchantActivityDO).from(merchantActivityDO).where(predicates).fetch();
        if (CollectionUtil.isEmpty(mcActivityList)) {
            return Collections.emptySet();
        }

        // 根据商家营销活动获取要过滤的skuId
        List<Long> mcActivityIdList = mcActivityList.stream().map(MerchantActivityDO::getId).collect(Collectors.toList());
        List<ActivityGoodsDO> mcGoodsList = goodsRepository.findByBelongTypeAndActivityIdIn(BelongTypeEnum.MERCHANT.getCode(), mcActivityIdList);

        return mcGoodsList.stream().map(ActivityGoodsDO::getSkuId).collect(Collectors.toSet());
    }

    /**
     * 判断叠加活动是否可用优惠券
     * @param tagList 活动标签BO
     * @return 返回结果
     */
    public boolean checkGoodsTagCanUserCoupon(List<ActivityGoodsTagBO> tagList) {
        Boolean checkAllowCoupon = null;
        for (ActivityGoodsTagBO activityGoodsTagBO : tagList) {
            JSONObject jsonObject = JSONUtil.parseObj(activityGoodsTagBO.getActivityDefinedBO());
            Boolean allowCoupon = jsonObject.getBool("allowCoupon");
            if (Objects.isNull(allowCoupon)) {
                return false;
            }

            if (Objects.isNull(checkAllowCoupon)) {
                checkAllowCoupon = allowCoupon;
            } else {
                if (!checkAllowCoupon.equals(allowCoupon)) {
                    return false;
                }
            }
        }

        if (Objects.isNull(checkAllowCoupon)) {
            return false;
        }

        return checkAllowCoupon;
    }

    /**
     * 判断叠加活动是否可用优惠券
     * @param activityGoodsDetailBO 活动
     * @return 返回结果
     */
    public boolean checkCanUserCoupon(ActivityGoodsDetailBO activityGoodsDetailBO) {
        return this.checkCanUserCoupon(Collections.singletonList(activityGoodsDetailBO));
    }

    /**
     * 判断叠加活动是否可用优惠券
     * @param activityGoodsBOList 活动
     * @return 返回结果
     */
    public boolean checkCanUserCoupon(List<ActivityGoodsDetailBO> activityGoodsBOList) {
        Boolean checkAllowCoupon = null;
        for (ActivityGoodsDetailBO activityGoodsDetailBO : activityGoodsBOList) {
            ActivityBO activityBO = activityGoodsDetailBO.getActivityBO();
            JSONObject jsonObject = JSONUtil.parseObj(activityBO.getActivityDefined());
            Boolean allowCoupon = jsonObject.getBool("allowCoupon");
            if (Objects.isNull(allowCoupon)) {
                return false;
            }

            if (Objects.isNull(checkAllowCoupon)) {
                checkAllowCoupon = allowCoupon;
            } else {
                if (!checkAllowCoupon.equals(allowCoupon)) {
                    return false;
                }
            }
        }
        if (Objects.isNull(checkAllowCoupon)) {
            return false;
        }

        return checkAllowCoupon;
    }

    /**
     * 检查活动适用商品
     * @param memberAndRoleIdBO 当前登录会员id和角色id
     * @param activityGoodsBOList 平台活动
     * @return 返回结果
     */
    public Wrapper<List<ActivityGoodsDetailBO>> checkPlatformActivity(MemberAndRoleIdBO memberAndRoleIdBO, List<ActivityGoodsDetailBO> activityGoodsBOList) {
        List<ActivityGoodsDetailBO> resultList = new ArrayList<>();

        if (CollectionUtils.isEmpty(activityGoodsBOList)) {
            return Wrapper.success(resultList);
        }

        PfSubMemberSuitableMemberVO subMemberSuitableMemberVO = null;
        if (Objects.nonNull(memberAndRoleIdBO)) {
            // 查询会员关系
            subMemberSuitableMemberVO = suitableMemberInfoComponent.getPlatformSubMemberSuitableMember(memberAndRoleIdBO.getMemberId(), memberAndRoleIdBO.getRoleId());
            if (Objects.isNull(subMemberSuitableMemberVO)) {
                return Wrapper.success();
            }
        }

        for (ActivityGoodsDetailBO activityGoodsDetailBO : activityGoodsBOList) {
            if (Objects.nonNull(memberAndRoleIdBO)) {
                PlatformSuitableMemberEnum suitableMemberEnum = this.checkPlatformMemberLevelRule((PlatformActivityBO) activityGoodsDetailBO.getActivityBO(), subMemberSuitableMemberVO);
                if (Objects.isNull(suitableMemberEnum)) {
                    continue;
                }
            }

            resultList.add(activityGoodsDetailBO);
        }

        return Wrapper.success(resultList);
    }

    /**
     * 检查活动适用商品
     * @param memberAndRoleIdBO 当前登录会员id和角色id
     * @param activityGoodsBOList 商家活动
     * @return 返回结果
     */
    public Wrapper<List<ActivityGoodsDetailBO>> checkMerchantActivity(MemberAndRoleIdBO memberAndRoleIdBO, List<ActivityGoodsDetailBO> activityGoodsBOList) {
        List<ActivityGoodsDetailBO> resultList = new ArrayList<>();

        if (CollectionUtils.isEmpty(activityGoodsBOList)) {
            return Wrapper.success(resultList);
        }

        List<MemberAndRoleIdBO> memberAndRoleIdBOList = activityGoodsBOList.stream().map(e -> new MemberAndRoleIdBO(e.getActivityBO().getMemberId(), e.getActivityBO().getRoleId())).collect(Collectors.toList());

        List<AtSubMemberSuitableMemberVO> subMemberSuitableMemberVOList = null;
        if (Objects.nonNull(memberAndRoleIdBO)) {
            // 查询会员关系
            subMemberSuitableMemberVOList = suitableMemberInfoComponent.listAbilitySubMemberSuitableMember(memberAndRoleIdBO.getMemberId(), memberAndRoleIdBO.getRoleId(), memberAndRoleIdBOList);
            if (CollectionUtils.isEmpty(subMemberSuitableMemberVOList)) {
                return Wrapper.success(Collections.emptyList());
            }
        }

        for (ActivityGoodsDetailBO activityGoodsDetailBO : activityGoodsBOList) {
            if (Objects.nonNull(memberAndRoleIdBO)) {
                AbilitySuitableMemberEnum suitableMemberEnum = this.checkMerchantMemberLevelRule(memberAndRoleIdBO, (MerchantActivityBO) activityGoodsDetailBO.getActivityBO(), subMemberSuitableMemberVOList);
                if (Objects.isNull(suitableMemberEnum)) {
                    continue;
                }
            }

            resultList.add(activityGoodsDetailBO);
        }

        return Wrapper.success(resultList);
    }

    /**
     * 检查平台活动的会员等级规则
     * @param platformActivityBO 平台活动
     * @param subMemberSuitableMemberVO 适用会员等级信息
     * @return 匹配到的适用会员
     */
    public PlatformSuitableMemberEnum checkPlatformMemberLevelRule(PlatformActivityBO platformActivityBO, PfSubMemberSuitableMemberVO subMemberSuitableMemberVO) {
        PlatformSuitableMemberEnum suitableMemberEnum = null;
        // 适用会员
        List<Integer> suitableMemberList = SuitableFieldComponent.parseCouponSuitableMember(platformActivityBO.getSuitableMember());
        if (suitableMemberList.contains(PlatformSuitableMemberEnum.NEW_PLATFORM_MEMBER.getCode()) && subMemberSuitableMemberVO.isNewMember()) {
            suitableMemberEnum = PlatformSuitableMemberEnum.NEW_PLATFORM_MEMBER;
        } else if (suitableMemberList.contains(PlatformSuitableMemberEnum.OLD_PLATFORM_MEMBER.getCode()) && subMemberSuitableMemberVO.isOldMember()) {
            suitableMemberEnum = PlatformSuitableMemberEnum.OLD_PLATFORM_MEMBER;
        } else {
            return null;
        }

        // 会员类型
        List<Integer> MemberTypeList = SuitableFieldComponent.parseMarketingMemberType(platformActivityBO.getSuitableMemberType());
        if (!MemberTypeList.contains(subMemberSuitableMemberVO.getMemberType())) {
            return null;
        }

        // 适用会员等级
        List<ActivityMemberLevelDO> memberLevelDOList = activityMemberLevelRepository.findByBelongTypeAndActivityId(BelongTypeEnum.PLATFORM.getCode(), platformActivityBO.getActivityId());
        if (!CollectionUtils.isEmpty(memberLevelDOList)) {
            // 会员类型, 会员角色, 会员等级类型, 会员等级
            if (!this.containsPlatformMemberLevel(memberLevelDOList, subMemberSuitableMemberVO)) {
                return null;
            }
        }

        return suitableMemberEnum;
    }

    /**
     * 检查商家活动的会员等级规则
     * @param memberAndRoleIdBO 当前登录会员id和角色id
     * @param merchantActivityBO 商家活动
     * @param subMemberSuitableMemberVOList 适用会员等级信息
     * @return 匹配到的适用会员
     */
    public AbilitySuitableMemberEnum checkMerchantMemberLevelRule(MemberAndRoleIdBO memberAndRoleIdBO, MerchantActivityBO merchantActivityBO, List<AtSubMemberSuitableMemberVO> subMemberSuitableMemberVOList) {
        // 查找会员关系
        AtSubMemberSuitableMemberVO subMemberSuitableMemberVO = subMemberSuitableMemberVOList.stream()
                .filter(e -> merchantActivityBO.getMemberId().equals(e.getUpperMemberId())
                        && merchantActivityBO.getRoleId().equals(e.getUpperRoleId())
                        && memberAndRoleIdBO.getMemberId().equals(e.getMemberId())
                        && memberAndRoleIdBO.getRoleId().equals(e.getRoleId())
                )
                .findFirst()
                .orElse(null);
        if (Objects.isNull(subMemberSuitableMemberVO)) {
            return null;
        }

        AbilitySuitableMemberEnum suitableMemberEnum = null;
        // 适用会员
        List<Integer> suitableUserList = SuitableFieldComponent.parseCouponSuitableUser(merchantActivityBO.getSuitableUser());
        // 是否为下级会员
        if (subMemberSuitableMemberVO.isSubMemberRelation()) {
            if (suitableUserList.contains(AbilitySuitableMemberEnum.NEW_MEMBER.getCode()) && subMemberSuitableMemberVO.isNewMember()) {
                // 新用户
                suitableMemberEnum = AbilitySuitableMemberEnum.NEW_MEMBER;
            } else if (suitableUserList.contains(AbilitySuitableMemberEnum.OLD_MEMBER.getCode()) && subMemberSuitableMemberVO.isOldMember()) {
                // 老用户
                suitableMemberEnum = AbilitySuitableMemberEnum.OLD_MEMBER;
            } else {
                return null;
            }

            // 判断适用会员等级
            List<ActivityMemberLevelDO> memberLevelDOList = activityMemberLevelRepository.findByBelongTypeAndActivityId(BelongTypeEnum.MERCHANT.getCode(), merchantActivityBO.getActivityId());
            if (!CollectionUtils.isEmpty(memberLevelDOList)) {
                if (!this.containsAbilityMemberLevel(memberLevelDOList, subMemberSuitableMemberVO)) {
                    return null;
                }
            }

        } else {
            if (suitableUserList.contains(AbilitySuitableMemberEnum.NEW_USER.getCode()) && subMemberSuitableMemberVO.isNewUser()) {
                // 新用户
                suitableMemberEnum = AbilitySuitableMemberEnum.NEW_USER;
            } else if (suitableUserList.contains(AbilitySuitableMemberEnum.OLD_USER.getCode()) && subMemberSuitableMemberVO.isOldUser()) {
                // 老用户
                suitableMemberEnum = AbilitySuitableMemberEnum.OLD_USER;
            } else {
                return null;
            }
        }

        return suitableMemberEnum;
    }

    // ===========================公共===========================

    /**
     * 是否符合会员类型, 会员角色, 会员等级类型, 会员等级
     * @param memberLevelDOList 会员等级配置
     * @param subMemberSuitableMemberVO 会员关系
     * @return true, false
     */
    public boolean containsAbilityMemberLevel(List<ActivityMemberLevelDO> memberLevelDOList, AtSubMemberSuitableMemberVO subMemberSuitableMemberVO) {
        for (ActivityMemberLevelDO activityMemberLevelDO : memberLevelDOList) {
            // 会员类型, 会员角色, 会员等级类型, 会员等级
            if (activityMemberLevelDO.getMemberType().equals(subMemberSuitableMemberVO.getMemberType())
                    && activityMemberLevelDO.getRoleType().equals(subMemberSuitableMemberVO.getRoleType())
                    && subMemberSuitableMemberVO.getRoleId().equals(activityMemberLevelDO.getRoleId())
                    && activityMemberLevelDO.getLevelType().equals(subMemberSuitableMemberVO.getLevelType())
                    && activityMemberLevelDO.getLevel().equals(subMemberSuitableMemberVO.getLevel())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否符合会员类型, 会员角色, 会员等级类型, 会员等级
     * @param memberLevelDOList 会员等级配置
     * @param subMemberSuitableMemberVO 会员关系
     * @return true, false
     */
    public boolean containsPlatformMemberLevel(List<ActivityMemberLevelDO> memberLevelDOList, PfSubMemberSuitableMemberVO subMemberSuitableMemberVO) {
        for (ActivityMemberLevelDO activityMemberLevelDO : memberLevelDOList) {
            // 会员类型, 会员角色, 会员等级类型, 会员等级
            if (activityMemberLevelDO.getMemberType().equals(subMemberSuitableMemberVO.getMemberType())
                    && activityMemberLevelDO.getRoleType().equals(subMemberSuitableMemberVO.getRoleType())
                    && activityMemberLevelDO.getRoleId().equals(subMemberSuitableMemberVO.getRoleId())
                    && activityMemberLevelDO.getLevelType().equals(subMemberSuitableMemberVO.getLevelType())
                    && activityMemberLevelDO.getLevel().equals(subMemberSuitableMemberVO.getLevel())) {
                return true;
            }
        }

        return false;
    }
}
